package com.caregiver.watch.business.care.service.impl;

import com.alibaba.fastjson2.JSON;
import com.caregiver.watch.business.care.dao.FenceRecipientRelationDao;
import com.caregiver.watch.business.care.dao.FenceSettingDao;
import com.caregiver.watch.business.care.enums.FenceRemindTypeEnum;
import com.caregiver.watch.business.care.enums.FenceStatus;
import com.caregiver.watch.business.care.helper.GeoFenceCheckerHelper;
import com.caregiver.watch.business.care.model.bo.FenceRecipientRelationBo;
import com.caregiver.watch.business.care.model.dto.AddFenceSettingParam;
import com.caregiver.watch.business.care.model.dto.DeleteFenceSettingParam;
import com.caregiver.watch.business.care.model.dto.EnableFenceSettingParam;
import com.caregiver.watch.business.care.model.dto.FenceLocation;
import com.caregiver.watch.business.care.model.dto.FenceRecipientInfo;
import com.caregiver.watch.business.care.model.dto.UpdateFenceSettingParam;
import com.caregiver.watch.business.care.model.po.FenceRecipientRelation;
import com.caregiver.watch.business.care.model.po.FenceSetting;
import com.caregiver.watch.business.care.model.vo.FenceRecipientVo;
import com.caregiver.watch.business.care.model.vo.FenceSettingDetailVo;
import com.caregiver.watch.business.care.model.vo.FenceSettingVo;
import com.caregiver.watch.business.care.service.CareRecipientService;
import com.caregiver.watch.business.care.service.FenceService;
import com.caregiver.watch.business.data.model.po.HealthDeviceLocation;
import com.caregiver.watch.business.user.helper.CareRecipientHelper;
import com.caregiver.watch.business.user.model.po.UserCareRecipient;
import com.caregiver.watch.business.user.model.po.UserDevice;
import com.caregiver.watch.business.user.service.UserDeviceService;
import com.caregiver.watch.business.user.utils.UserInfoUtils;
import com.caregiver.watch.common.constant.Constants;
import com.caregiver.watch.common.exception.BaseException;
import com.caregiver.watch.common.helper.TransactionalHelper;
import com.caregiver.watch.common.utils.collection.ListUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.function.Function;

import static com.caregiver.watch.common.constant.NumberConstants.ONE;
import static com.caregiver.watch.common.constant.NumberConstants.THREE;
import static com.caregiver.watch.common.constant.NumberConstants.ZERO;

/**
 * @program: caregiver-watch
 * @author: 疆戟
 * @create: 2025-10-05 21:21
 */
@AllArgsConstructor
@Slf4j
@Service
public class FenceServiceImpl implements FenceService {

    private final FenceSettingDao fenceSettingDao;
    private final FenceRecipientRelationDao fenceRecipientRelationDao;
    private final TransactionalHelper transactionalHelper;
    private final ExecutorService fenceAlarmWorkThreadPool;
    private final CareRecipientService careRecipientService;
    private final UserDeviceService userDeviceService;
    private final CareRecipientHelper careRecipientHelper;


    @Override
    public List<FenceSettingVo> queryFenceSettingList() {
        Long userId = UserInfoUtils.getUserId();
        List<FenceSetting> fenceSettingList = fenceSettingDao.selectByUserId(userId);
        List<Long> fenceIds = ListUtils.mapDistinct(fenceSettingList, FenceSetting::getId);
        final Map<Long, List<FenceRecipientRelationBo>> fenceIdToRecipientRelationsMap = queryFenceIdToRecipientRelationsMap(fenceIds);
        return ListUtils.map(fenceSettingList, fenceSetting -> buildFenceSettingVo(fenceSetting, fenceIdToRecipientRelationsMap));
    }

    /**
     * 查询关联的照护人信息
     *
     * @param fenceIds 围栏ID列表
     * @return
     */
    private Map<Long, List<FenceRecipientRelationBo>> queryFenceIdToRecipientRelationsMap(List<Long> fenceIds) {
        if (CollectionUtils.isEmpty(fenceIds)) {
            return Collections.emptyMap();
        }
        return ListUtils.groupingBy(fenceRecipientRelationDao.selectByFenceIds(fenceIds), FenceRecipientRelationBo::getFenceId);
    }

    /**
     * 构建围栏设置VO
     *
     * @param fenceSetting 围栏设置
     * @param fenceIdToRecipientRelationsMap 关联的照护人信息
     * @return
     */
    public FenceSettingVo buildFenceSettingVo(FenceSetting fenceSetting,
                                              final Map<Long, List<FenceRecipientRelationBo>> fenceIdToRecipientRelationsMap) {
        FenceSettingVo fenceSettingVo = new FenceSettingVo();
        fenceSettingVo.setFenceId(fenceSetting.getId());
        fenceSettingVo.setFenceName(fenceSetting.getFenceName());
        fenceSettingVo.setStartTime(fenceSetting.getStartTime());
        fenceSettingVo.setEndTime(fenceSetting.getEndTime());
        fenceSettingVo.setFenceRemindType(fenceSetting.getFenceRemindType());
        fenceSettingVo.setEnable(fenceSetting.getEnable());
        List<FenceRecipientRelationBo> bos = fenceIdToRecipientRelationsMap.get(fenceSettingVo.getFenceId());
        List<String> effectiveRecipientNames = ListUtils.map(bos, FenceRecipientRelationBo::getRecipientName);
        fenceSettingVo.setEffectiveRecipientNames(effectiveRecipientNames);
        return fenceSettingVo;
    }

    @Override
    public FenceSettingDetailVo queryFenceSetting(Long fenceId) {
        Long userId = UserInfoUtils.getUserId();
        FenceSetting fenceSetting = fenceSettingDao.selectById(userId, fenceId);
        if (Objects.isNull(fenceSetting)) {
            throw new BaseException("围栏设置不存在");
        }
        Map<Long, List<FenceRecipientRelationBo>> fenceIdToRecipientRelationsMap = queryFenceIdToRecipientRelationsMap(Collections.singletonList(fenceId));
        FenceSettingDetailVo fenceSettingDetailVo = new FenceSettingDetailVo();
        fenceSettingDetailVo.setFenceId(fenceSetting.getId());
        fenceSettingDetailVo.setFenceName(fenceSetting.getFenceName());
        fenceSettingDetailVo.setStartTime(fenceSetting.getStartTime());
        fenceSettingDetailVo.setEndTime(fenceSetting.getEndTime());
        fenceSettingDetailVo.setFenceRemindType(fenceSetting.getFenceRemindType());
        fenceSettingDetailVo.setEnable(fenceSetting.getEnable());
        List<FenceRecipientRelationBo> bos = fenceIdToRecipientRelationsMap.get(fenceSettingDetailVo.getFenceId());
        List<FenceRecipientInfo> effectiveRecipients = ListUtils.map(bos, bo -> {
            String recipientAvatar = careRecipientHelper.getRecipientAvatar(bo.getRelationship());
            return FenceRecipientInfo.build(bo.getRecipientId(), bo.getRecipientDeviceUuid(), bo.getRecipientName(), recipientAvatar);
        });
        fenceSettingDetailVo.setEffectiveRecipients(effectiveRecipients);
        if (StringUtils.isNotBlank(fenceSetting.getFenceData())) {
            fenceSettingDetailVo.setFenceLocations(JSON.parseArray(fenceSetting.getFenceData(), FenceLocation.class));
        }
        return fenceSettingDetailVo;
    }

    @Override
    public Boolean addFenceSetting(AddFenceSettingParam param) {
        List<FenceLocation> fenceLocations = param.getFenceLocations();
        if (CollectionUtils.isEmpty(fenceLocations)) {
            throw new BaseException("围栏位置不能为空");
        }
        if (fenceLocations.size() < THREE) {
            throw new BaseException("围栏位置不能少于三个");
        }
        Long userId = UserInfoUtils.getUserId();
        FenceSetting fenceSetting = param.toPo(userId);
        List<FenceRecipientInfo> fenceRecipientInfos = param.getFenceRecipientInfos();
        List<FenceRecipientRelation> relations = ListUtils.map(fenceRecipientInfos, info -> {
            FenceRecipientRelation relation = new FenceRecipientRelation();
            relation.setRecipientId(info.getRecipientId());
            relation.setRecipientDeviceUuid(info.getRecipientDeviceUuId());
            return relation;
        });
        transactionalHelper.execute(() -> {
            fenceSettingDao.insert(fenceSetting);
            if (CollectionUtils.isEmpty(relations)) {
                return;
            }
            relations.forEach(relation -> relation.setFenceId(fenceSetting.getId()));
            fenceRecipientRelationDao.batchInsert(relations);
        });
        return Boolean.TRUE;
    }

    @Override
    public Boolean updateFenceSetting(UpdateFenceSettingParam param) {
        Long fenceId = param.getFenceId();
        Long userId = UserInfoUtils.getUserId();
        Boolean exist = fenceSettingDao.existById(userId, fenceId);
        if (BooleanUtils.isNotTrue(exist)) {
            throw new BaseException("围栏设置不存在");
        }
        FenceSetting updateFenceSetting = param.toPo(userId);
        List<FenceRecipientRelation> fenceRecipientRelations = fenceRecipientRelationDao.selectByFenceId(fenceId);
        Map<String, FenceRecipientRelation> recipientIdAndDeviceUuidToRelationMap = ListUtils.toMap(fenceRecipientRelations,
                item -> item.getRecipientId() + Constants.DASH + item.getRecipientDeviceUuid());
        // 对比出新增和删除的被照护人
        List<FenceRecipientInfo> fenceRecipientInfos = param.getFenceRecipientInfos();
        if (CollectionUtils.isEmpty(fenceRecipientInfos)) {
            transactionalHelper.execute(() -> {
                // 更新围栏设置
                fenceSettingDao.updateById(updateFenceSetting);
                // 删除所有被照护人
                fenceRecipientRelationDao.deleteByFenceId(fenceId);
            });
            return Boolean.TRUE;
        }
        List<FenceRecipientRelation> insertRelations = new ArrayList<>();
        List<Long> deleteRelationIds = new ArrayList<>();
        for (FenceRecipientInfo info : fenceRecipientInfos) {
            String key = info.getRecipientId() + Constants.DASH + info.getRecipientDeviceUuId();
            // 对比一个删除一个 剩下的就是需要删除的
            FenceRecipientRelation relation = recipientIdAndDeviceUuidToRelationMap.remove(key);
            if (Objects.nonNull(relation)) {
                continue;
            }
            // 新增
            FenceRecipientRelation insertRelation = new FenceRecipientRelation();
            insertRelation.setFenceId(fenceId);
            insertRelation.setRecipientId(info.getRecipientId());
            insertRelation.setRecipientDeviceUuid(info.getRecipientDeviceUuId());
            insertRelations.add(insertRelation);
        }
        recipientIdAndDeviceUuidToRelationMap.forEach((key, relation) -> deleteRelationIds.add(relation.getId()));
        transactionalHelper.execute(() -> {
            fenceSettingDao.updateById(updateFenceSetting);
            if (CollectionUtils.isNotEmpty(insertRelations)) {
                fenceRecipientRelationDao.batchInsert(insertRelations);
            }
            if (CollectionUtils.isNotEmpty(deleteRelationIds)) {
                fenceRecipientRelationDao.deleteByIds(deleteRelationIds);
            }
        });
        return Boolean.TRUE;
    }

    @Override
    public Boolean enableFenceSetting(EnableFenceSettingParam param) {
        Long fenceId = param.getFenceId();
        Long userId = UserInfoUtils.getUserId();
        Boolean exist = fenceSettingDao.existById(userId, fenceId);
        log.info("enableFenceSetting userId: {}, param: {}", userId, param);
        if (BooleanUtils.isNotTrue(exist)) {
            throw new BaseException("围栏设置不存在");
        }
        FenceSetting fenceSetting = new FenceSetting();
        fenceSetting.setId(fenceId);
        fenceSetting.setEnable(BooleanUtils.isTrue(param.getEnable()) ? ONE : ZERO);
        return fenceSettingDao.updateById(fenceSetting) > ZERO;
    }

    @Override
    public Boolean deleteFenceSetting(DeleteFenceSettingParam param) {
        Long fenceId = param.getFenceId();
        Long userId = UserInfoUtils.getUserId();
        return transactionalHelper.execute(() -> {
            boolean success = fenceSettingDao.deleteById(userId, fenceId) > ZERO;
            if (BooleanUtils.isTrue(success)) {
                fenceRecipientRelationDao.deleteByFenceId(fenceId);
            }
            return success;
        });
    }

    @Override
    public void fenceAlarmHandle(Long userId, String deviceId, List<HealthDeviceLocation> deviceLocations) {
        if (Objects.isNull(userId) || StringUtils.isBlank(deviceId)) {
            return;
        }
        if (CollectionUtils.isEmpty(deviceLocations)) {
            return;
        }
        fenceAlarmWorkThreadPool.execute(() -> {
            LocalTime now = LocalTime.now();
            // 获取开启的围栏信息
            FenceSetting fenceSetting = fenceSettingDao.queryCurrentTimeEnabled(userId, deviceId, now);
            if (Objects.isNull(fenceSetting)) {
                return;
            }
            List<FenceLocation> fenceLocations = JSON.parseArray(fenceSetting.getFenceData(), FenceLocation.class);
            if (CollectionUtils.isEmpty(fenceLocations)) {
                return;
            }
            FenceRemindTypeEnum fenceRemindType = fenceSetting.getFenceRemindType();
            FenceStatus trackFenceStatus = GeoFenceCheckerHelper.getTrackFenceStatus(deviceLocations, fenceLocations);
        });
    }

    @Override
    public FenceRecipientVo queryFenceRecipientList() {
        Long userId = UserInfoUtils.getUserId();
        // 查询监护人设备
        List<UserDevice> guardianDevices = userDeviceService.queryAllContactDeviceList(userId);
        List<Long> recipientIds = ListUtils.map(guardianDevices, UserDevice::getRecipientId);
        // 查询监护人
        List<UserCareRecipient> careRecipientList = careRecipientService.queryUserCareRecipientByIds(userId, recipientIds);
        if (CollectionUtils.isEmpty(careRecipientList)) {
            return new FenceRecipientVo();
        }
        Map<Long, UserCareRecipient> recipientIdToNameMap = ListUtils.toMap(careRecipientList, UserCareRecipient::getRecipientId, Function.identity());
        List<FenceRecipientInfo> recipientInfos = ListUtils.map(guardianDevices, device -> {
            UserCareRecipient recipient = recipientIdToNameMap.get(device.getRecipientId());
            if (Objects.isNull(recipient)) {
                return null;
            }
            String recipientAvatar = careRecipientHelper.getRecipientAvatar(recipient.getRelationship());
            return FenceRecipientInfo.build(device.getRecipientId(), device.getDeviceUuid(), recipient.getName(), recipientAvatar);
        });
        return FenceRecipientVo.build(recipientInfos);
    }
}
